#!/usr/bin/python
# A really simple remote control for HDTV/DVB receivers
# Nigel Sim <nigel.sim@gmail.com>

# Environment variables
# GHDTV_GLADE_PATH - path to glade files
# GHDTV_CHANNEL_PATH - path to channel.conf file

import pygtk
pygtk.require("2.0")

import gtk
import gtk.glade

import gobject
#import gst
from dvb3 import frontend, dmx
import os, signal, math

import channels

class TV:
	"""
	A Facade class for using the DVB
	"""
	def __init__(self, adaptor=0):
		self.fe = frontend.Frontend(adaptor)
		self.dmA = dmx.Demux(adaptor)
		self.dmV = dmx.Demux(adaptor)
		return

	def getSNR(self):
		return self.fe.read_snr()

	def getSignal(self):
		return self.fe.read_signal_strength()

	def getBER(self):
		"""
		Returns the Bit Error Rate
		"""
		return self.fe.read_ber()

	def setChannel(self, parameters, vpid, apid):
		"""
		Sets the channels from the parameter and PIDs
		"""
		self.fe.set_frontend(parameters)
		self.dmV.stop()
		self.dmA.stop()
		self.dmV.set_pes_filter(vpid, dmx.DMX_IN_FRONTEND, dmx.DMX_OUT_TS_TAP, dmx.DMX_PES_VIDEO, dmx.DMX_IMMEDIATE_START)
		self.dmA.set_pes_filter(apid, dmx.DMX_IN_FRONTEND, dmx.DMX_OUT_TS_TAP, dmx.DMX_PES_AUDIO, dmx.DMX_IMMEDIATE_START)	
		self.dmV.start()
		self.dmA.start()

class ChannelChanger:
	"""
	The GTK GUI (view/controller) for handing channel changes
	"""
	playerCmd = 'mplayer'
	playerArgs = ['','/dev/dvb/adapter0/dvr0', '-really-quiet','-slave','-nomouseinput', '-autosync', '1']
	#playerCmd = 'xine'
	#playerArgs = ['','/dev/dvb/adapter0/dvr0','-g']
	def __init__(self):
		gladePath = os.getenv("GHDTV_GLADE_PATH")
		channelPath = os.getenv("GHDTV_GLADE_PATH")
		if gladePath != None:
			if gladePath[-1:] != '/':
				gladePath += '/'
		else:
			gladePath = './'
		if channelPath != None:
			if channelPath[-1:] != '/':
				channelPath += '/'
		else:
			channelPath = './'
		self.glade = gtk.glade.XML(gladePath+'ghdtv.glade', 'control')
		self.channelList = self.glade.get_widget('channelList')
		self.window = self.glade.get_widget('control')
		self.signal = self.glade.get_widget('signal')
		self.snr = self.glade.get_widget('snr')
		self.glade.signal_autoconnect(self)

		self.tv = TV()

		self.playerPID = None

		# Setup the column renderer
		self.channelList.append_column(gtk.TreeViewColumn("Channel", gtk.CellRendererText(), text=0))

		# Load the channel list
		self.channels = channels.Channels()
		self.channels.read(open(channelPath+'channels.conf'))
		l = gtk.ListStore(gobject.TYPE_STRING)
		for i in self.channels.channels:
			l.append([i])
		self.channelList.set_model(l)

		self.timer = gobject.timeout_add(1000, self.on_refresh, self)

	def on_control_destroy(self, data):
		"""
		Exit the program
		"""
		self.cleanup()
		gtk.main_quit()

	def on_cmdQuit_clicked(self, data):
		self.cleanup()
		gtk.main_quit()

	def on_channelList_row_activated(self, tree, loc, col):
		"""
		A new channel row is selected, clean up, retune, and start up again
		"""
		if self.playerPID != None:
			os.kill(self.playerPID, signal.SIGQUIT)
		iter = tree.get_model().get_iter(loc)
		channel = tree.get_model().get_value(iter, 0)
		self.tv.setChannel(self.channels.get_parameter(channel), self.channels.get_vpid(channel), self.channels.get_apid(channel))
		self.playerPID = os.spawnvp(os.P_NOWAIT, self.playerCmd, self.playerArgs)
		print self.playerPID

	def on_refresh(self, data):
		snr = self.tv.getSNR()
		if snr == 0:
			self.snr.set_text( "SNR: N/A" )
		else:
			self.snr.set_text( "SNR: %.1f "% (math.log(snr)/16*100) )
		signal = self.tv.getSignal()
		if signal == 0:
			self.signal.set_text( "Signal: N/A" )
		else:
			self.signal.set_text( "Signal: %.1f "% (math.log(signal)/16*100) )
		self.timer = gobject.timeout_add(10000, self.on_refresh, self)

	def cleanup(self):
		"""
		Close down any running mplayers, and clean up
		"""
		if self.playerPID != None:
			os.kill(self.playerPID, signal.SIGQUIT)


if __name__ == '__main__':
	c = ChannelChanger()
	gtk.main()
